// # c++
#include <string>
// ##

#include "models/InputTestModel.h"
//#include "models/TwoPhasesParrallelDBOperationModelGenerator.h"
#include "models/OneStepOnePassDbOperationModel.h"
#include "models/TwoStepOnePassDbOperationModel.h"
#include "models/ThreeStepOnePassDbOperationModel.h"
#include "models/ArithmeticOperationModelGenerator.h"
#include "models/AggregationFunctionModelGenerator.h"

namespace jm4bbx {


	std::string getIntAdditionModel(int parallelismLevel, 
		const std::string& lineEnd) {
			InputBoxConfiguration f = {"A", 0};
			InputBoxConfiguration s = {"B", 0};
			
			ArithmeticOperationModelGenerator amg(parallelismLevel, "DATA_BOX", 
				f, s, "ADDITION_INTEGER", "INTEGER_OUTPUT", "IntegerKeyRecord");
			
			return amg.generateModel(lineEnd);

	}


	std::string getAggregateFunctionModel(int parallelismLevel, 
		const std::string& lineEnd, const std::string& aggF, 
		const std::string& aggR) {

			InputBoxConfiguration conf = {"A", 0};
			
			AggregationFunctionModelGenerator amg(parallelismLevel, "DATA_BOX", 
				conf, aggF, aggR, "INTEGER_OUTPUT");

			return amg.generateModel(lineEnd);
	}

	std::string getSumModel(int parallelismLevel, 
		const std::string& lineEnd) {
			return getAggregateFunctionModel(parallelismLevel, lineEnd, 
				"SUM_INTEGER", "SUM_RESULT_INTEGER");
	}
	std::string getMinModel(int parallelismLevel, 
		const std::string& lineEnd) {
			return getAggregateFunctionModel(parallelismLevel, lineEnd, 
				"MIN_INTEGER", "MIN_RESULT_INTEGER");
	}

	std::string getMaxModel(int parallelismLevel, 
		const std::string& lineEnd) {
			return getAggregateFunctionModel(parallelismLevel, lineEnd, 
				"MAX_INTEGER", "MAX_RESULT_INTEGER");
	}

	std::string getAvgModel(int parallelismLevel, 
		const std::string& lineEnd) {
			return getAggregateFunctionModel(parallelismLevel, lineEnd, 
				"AVG_INTEGER", "AVG_RESULT_INTEGER");
	}




	std::string getEliminationModel(int parallelismLevel, 
		const std::string& lineEnd, const InputBoxConfiguration& conf,
		const std::string& inputName, bool isInt) {

			const char* elimBox = isInt ? "ELIMINATION_INTEGER" : "ELIMINATION_STRING";
			const char* recType = isInt ? "IntegerKeyRecord" : "StringKeyRecord";

			OneStepOnePassDbOperationModel amg(parallelismLevel, inputName, 
				conf, elimBox, "BIN_INDEX_OUTPUT", 
				"first", recType);

			return amg.generateModel(lineEnd);

	}

	std::string getStrHDEliminationModel(int parallelismLevel, 
		const std::string& lineEnd) {

			InputBoxConfiguration f = {"C", 1};
			
			return getEliminationModel(parallelismLevel, lineEnd, f,  "DATA_BOX", 
				false);
	}


	std::string getHashModel(int parallelismLevel, const std::string& lineEnd, 
		const InputBoxConfiguration& first, const InputBoxConfiguration& second, 
		const std::string& inp, bool isInt, const std::string& activityBoxName,
		bool isBagVersion) {

			const char* hashBox = isInt ? "HASH_INTEGER" : "HASH_STRING";
			const char* recType = isInt ? "IntegerKeyRecord" : 
				"StringKeyRecord";

			TwoStepOnePassDbOperationModel amg(parallelismLevel, inp, 
				first, second,	hashBox, activityBoxName, "BIN_INDEX_OUTPUT", 
				"both", recType, isBagVersion);

			return amg.generateModel(lineEnd);
	}

	std::string getHashJoinModel(int parallelismLevel, 
		const std::string& lineEnd, const InputBoxConfiguration& first, 
		const InputBoxConfiguration& second, const std::string& inp, 
		bool isInt) {

			const char* joinBox = isInt ? "HASH_JOIN_INTEGER" : 
				"HASH_JOIN_STRING";

			return getHashModel(parallelismLevel, lineEnd, first, second, inp, 
				isInt, joinBox, true);
	}


	std::string getHashIntersectionModel(int parallelismLevel, 
		const std::string& lineEnd, const InputBoxConfiguration& first, 
		const InputBoxConfiguration& second, const std::string& inp, 
		bool isInt, bool isBagVersion) {

			const char* intersectionBox = isInt ? "HASH_INTERSECTION_INTEGER" : 
				"HASH_INTERSECTION_STRING";

			return getHashModel(parallelismLevel, lineEnd, first, second, inp, 
				isInt, intersectionBox, isBagVersion);
	}

	std::string getHashSecondOperandSubtractionModel(int parallelismLevel, 
		const std::string& lineEnd, const InputBoxConfiguration& first, 
		const InputBoxConfiguration& second, const std::string& inp, bool isInt,
		bool bagVersion) {

			const char* hashBox = isInt ? "HASH_INTEGER" : "HASH_STRING";
			const char* activityBox = isInt ? "HASH_S_SUBTRACTION_INTEGER" : 
				"HASH_S_SUBTRACTION_STRING";
			const char* recType = isInt ? "IntegerKeyRecord" : 
				"StringKeyRecord";

			TwoStepOnePassDbOperationModel amg(parallelismLevel, inp, 
				first, second,	hashBox, activityBox, "BIN_INDEX_OUTPUT", 
				"second", recType, bagVersion);

			return amg.generateModel(lineEnd);
	}

	std::string getHashFirstOperandSubtractionModel(int parallelismLevel, 
		const std::string& lineEnd, const InputBoxConfiguration& first, 
		const InputBoxConfiguration& second, const std::string& inp, bool isInt,
		bool bagVersion) {

			const char* hashBox = isInt ? "HASH_INTEGER" : "HASH_STRING";
			const char* activityBox = isInt ? "HASH_F_SUBTRACTION_INTEGER" : 
				"HASH_F_SUBTRACTION_STRING";
			const char* recType = isInt ? "IntegerKeyRecord" : 
				"StringKeyRecord";

			ThreeStepOnePassDbOperationModel amg(parallelismLevel, inp, 
				first, second,	hashBox, activityBox, "BIN_INDEX_OUTPUT", "first", 
				recType, bagVersion, "HASH_FR_SUBTRACTION_STRING");

			return amg.generateModel(lineEnd);
	}

	////////////////////////////////////////////////////////////////////////////
	////////////////////////////////////////////////////////////////////////////
	////////////////////////////////////////////////////////////////////////////

	std::string getStrHDHashJoinModel(int parallelismLevel, 
		const std::string& lineEnd = "") {

			InputBoxConfiguration f = {"A", 1};
			InputBoxConfiguration s = {"B", 1};

			return getHashJoinModel(parallelismLevel, lineEnd, f, s, "DATA_BOX", 
				false);
	}


	std::string getStrHDHashIntersectionModel(int parallelismLevel, 
		const std::string& lineEnd, bool isInt, bool isBagVersion) {

			InputBoxConfiguration f = {"A", isInt ? 0 : 1 };
			InputBoxConfiguration s = {"B", isInt ? 0 : 1 };
			return getHashIntersectionModel(parallelismLevel, lineEnd, f, s, 
				"DATA_BOX", isInt, isBagVersion);
	}

	std::string getHDHashSecondSubtractionModel(int parallelismLevel, 
		const std::string& lineEnd, bool isInt, bool bagVersion) {

			InputBoxConfiguration f = {"A", isInt ? 0 : 1};		
			InputBoxConfiguration s = {"B", isInt ? 0 : 1};

			return getHashSecondOperandSubtractionModel(parallelismLevel, 
				lineEnd, f, s, "DATA_BOX", isInt, bagVersion);

	}

	std::string getHDHashFirstSubtractionModel(int parallelismLevel, 
		const std::string& lineEnd, bool isInt, bool bagVersion) {
			InputBoxConfiguration f = {"A", isInt ? 0 : 1};		
			InputBoxConfiguration s = {"B", isInt ? 0 : 1};

			return getHashFirstOperandSubtractionModel(parallelismLevel, 
				lineEnd, f, s, "DATA_BOX", isInt, bagVersion);
	}

	////////////////////////////////////////////////////////////////////////////


	std::string getIntCsvHashJoinModel(const std::string& file1, 
		const std::string& file2, int parallelismLevel, 
		const std::string& lineEnd = "") {

			InputBoxConfiguration f = {file1, 0};
			InputBoxConfiguration s = {file2, 0};

			return getHashJoinModel(parallelismLevel, lineEnd, f, s, "CSV_BOX", 
				false);
	}


	std::string getIntCsvHashIntersectionModel(int parallelismLevel, 
		const std::string& lineEnd, bool isInt, bool isBagVersion) {

			InputBoxConfiguration f = {"A", isInt ? 0 : 1 };
			InputBoxConfiguration s = {"B", isInt ? 0 : 1 };
			return getHashIntersectionModel(parallelismLevel, lineEnd, f, s, 
				"DATA_BOX", isInt, isBagVersion);
	}

	std::string getIntCsvSecondSubtractionModel(int parallelismLevel, 
		const std::string& lineEnd, bool isInt, bool bagVersion) {

			InputBoxConfiguration f = {"A", isInt ? 0 : 1};		
			InputBoxConfiguration s = {"B", isInt ? 0 : 1};

			return getHashSecondOperandSubtractionModel(parallelismLevel, 
				lineEnd, f, s, "DATA_BOX", isInt, bagVersion);

	}

	std::string getIntCsvFirstSubtractionModel(int parallelismLevel, 
		const std::string& lineEnd, bool isInt, bool bagVersion) {
			InputBoxConfiguration f = {"A", isInt ? 0 : 1};		
			InputBoxConfiguration s = {"B", isInt ? 0 : 1};

			return getHashFirstOperandSubtractionModel(parallelismLevel, 
				lineEnd, f, s, "DATA_BOX", isInt, bagVersion);
	}


} // namespace jm4bbx
